/*
 * list.h
 *
 *  Created on: Feb 26, 2011
 *      Author: thienlong
 */

#ifndef LIST_H_
#define LIST_H_
#include "collection.h"
#include "map.h"
#include <time.h>
typedef struct vector vector;
struct vector {
	object *items;
	int size;
	int capacity;
	eq_fn eqfn;
	del_fn delfn;
	mem_storage *storage;
	mem_type mtype;
};

#define VECTOR_INIT(vec, cap, eqcb, delcb, memstorage, type) { \
	if (cap <= 0) { \
		(vec)->capacity = 16; \
	} else { \
		(vec)->capacity = cap; \
	} \
	(vec)->size = 0; \
	(vec)->eqfn = eqcb; \
	(vec)->delfn = delcb; \
	(vec)->storage = memstorage; \
	(vec)->items = calloc((vec)->capacity, sizeof(object)); \
	(vec)->mtype = type; \
}
/**
 * construct new vector object. Note that vector allow add same object many times
 * but we must be careful when remove or free object.
 */
extern vector* vector_new(int capacity, eq_fn eqfn, del_fn delfn,
		mem_storage *storage, mem_type type);
/**
 * add a given %obj to tail of vector %v
 */
extern void vector_add(vector *v, object obj);
/**
 * insert a given %obj to specified %index
 */
extern void vector_insert(vector *v, int index, object obj);
/**
 * replace old val in specified index position by a given obj.
 * Return old val object
 */
extern object vector_set(vector *v, int index, object obj);
/**
 * get a object in specified index
 */
extern object vector_get(vector *v, int index);
/**
 * remove object in specified index.
 * Return object at specified index.
 */
extern object vector_del(vector *v, int index);
/**
 * remove  first occurrence of the specified object. If the list does not contain the element, it is
 * unchanged.  More formally, removes the element with the lowest index. removing by calling del_fn call back (be careful may be obj point same address of object in vector).
 * Return true if object was removed successfully otherwise false
 */
extern bool vector_remove(vector *v, object obj);
/**
 * removes the last element of a given vector
 */
extern object vector_pop(vector *v);
/**
 * detach first occurrence of the specified object from vector
 */
extern object vector_detach(vector *v, object obj);

/**
 * detach all reference point same a given obj's address.
 * Return true if it was removed otherwise false.
 */
extern bool vector_detach_ref(vector *v, object obj);
/**
 * finding index of first matched object
 */
extern int vector_first(vector *v, object obj);
/**
 * finding index of last matched object
 */
extern int vector_last(vector *v, object obj);
/**
 * clear vector's data. if del = true then call del_fn on each object data.
 * Note: if one object was add two times then it will cause call del_fn on that object two times.
 * That maybe cause error. In this case should loop over vector to free object data manually, then call
 * vector_clear(v, false)
 */
extern void vector_clear(vector *v, bool del);
/**
 * free a given vector and all data inside it by calling del_cb function.
 * first it call vector_clear(v, true) then free itself.
 * @see int vector_last(vector *v, object obj) for more information
 */
extern void vector_free(vector **v);
/**
 * similar with vector_free but it check items refer to same address
 */
extern void vector_free_ref(vector **v);

/********************ARRAY CONCURRENT QUEUE's API*********************/
typedef struct array_cqueue {
	object *items;
	int take_idx;
	int put_idx;
	int count;
	int capacity;
	pthread_mutex_t lock;
	pthread_cond_t not_empty;
	pthread_cond_t not_full;
} array_cqueue;

extern array_cqueue* acqueue_new(int capacity);
/**
 * Inserts the specified element at the tail of this queue if it is
 * possible to do so immediately without exceeding the queue's capacity,
 * returning <tt>true</tt> upon success and <tt>false</tt> if this queue
 * is full.
 *
 * @throws NullPointerException if the specified element is null
 */
extern bool acqueue_add(array_cqueue *queue, object obj);

/**
 * Inserts the specified element at the tail of this queue, waiting
 * for space to become available if the queue is full.
 *
 * @throws InterruptedException {@inheritDoc}
 * @throws NullPointerException {@inheritDoc}
 */
extern void acqueue_put(array_cqueue *queue, object obj);

/**
 * Inserts the specified element at the tail of this queue, waiting
 * up to the specified wait time for space to become available if
 * the queue is full.
 *
 * @throws InterruptedException {@inheritDoc}
 * @throws NullPointerException {@inheritDoc}
 */
extern bool acqueue_offer(array_cqueue *queue, object obj, long timeout);

/**
 * Inserts the specified element at the tail of this queue, waiting
 * up to the specified wait time for space to become available if
 * the queue is full. ABSTIME is an
 absolute time specification; zero is the beginning of the epoch
 (00:00:00 GMT, January 1, 1970).
 *
 * @throws InterruptedException {@inheritDoc}
 * @throws NullPointerException {@inheritDoc}
 */
extern bool acqueue_insert(array_cqueue *queue, object obj,
		struct timespec *abstime);

/*Retrieves and removes the head of this queue, or returns null if this queue is empty.

 Returns:
 the head of this queue, or null if this queue is empty*/
extern object acqueue_remove(array_cqueue *queue);

/*Retrieves and removes the head of this queue, waiting if necessary until an element becomes available.
 Specified by: take() in BlockingQueue

 Returns:
 the head of this queue*/
extern object acqueue_take(array_cqueue *queue);
/*
 Retrieves and removes the head of this queue, waiting up to the specified wait time if necessary for an element to become available.
 Specified by: poll(...) in BlockingQueue

 Parameters:
 timeout how long to wait before giving up, in units of unit
 unit a TimeUnit determining how to interpret the timeout parameter
 Returns:
 the head of this queue, or null if the specified waiting time elapses before an element is available*/
extern object acqueue_poll(array_cqueue *queue, long timeout);

/*
 Retrieves and removes the head of this queue, waiting up to the specified wait time if necessary for an element to become available.
 Specified by: poll(...) in BlockingQueue

 Parameters:
 timeout how long to wait before giving up, in units of unit
 unit a TimeUnit determining how to interpret the timeout parameter
 Returns:
 the head of this queue, or null if the specified waiting time elapses before an element is available*/
extern object acqueue_pop(array_cqueue *queue, struct timespec *abstime);

/*Retrieves, but does not remove, the head of this queue, or returns null if this queue is empty.
 Specified by: peek() in Queue

 Returns:
 the head of this queue, or null if this queue is empty*/
extern object acqueue_peek(array_cqueue *queue);

/*Returns the number of elements in this queue.
 Specified by: size() in Collection, Overrides: size() in AbstractCollection

 Returns:
 the number of elements in this queue*/
extern int acqueue_size(array_cqueue *queue);

/**
 * Atomically removes all of the elements from this queue.
 * The queue will be empty after this call returns.
 */
extern void acqueue_clear(array_cqueue *queue, del_fn delcb,
		mem_storage *storage, mem_type type);

typedef hashmap hashset;
#define hset_add(set, obj) hmap_put(set, obj, (val) 1);
#define hset_size(set) hmap_size(set);
#define hset_remove(set, obj) hmap_remove(set, obj);
#define hset_clear(set, del) hmap_clear(set, del);
#endif /* LIST_H_ */
